🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / domain / src / commonMain / kotlin / org / meshtastic / core / domain / usecase / settings / InstallProfileUseCase.kt
Displaying Raw • Download
core/domain/src/commonMain/kotlin/org/meshtastic/core/domain/usecase/settings/InstallProfileUseCase.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 8.61 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.domain.usecase.settings
Tff7b72import T7ee787kotlinx.coroutines.NonCancellable
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787org.koin.core.annotation.Single
Tff7b72import T7ee787org.meshtastic.core.common.util.CommonUri
Tff7b72import T7ee787org.meshtastic.core.model.Position
Tff7b72import T7ee787org.meshtastic.core.model.util.ChannelReplacementPlan
Tff7b72import T7ee787org.meshtastic.core.model.util.MalformedMeshtasticUrlException
Tff7b72import T7ee787org.meshtastic.core.model.util.toChannelReplacementPlan
Tff7b72import T7ee787org.meshtastic.core.model.util.toChannelSet
Tff7b72import T7ee787org.meshtastic.core.repository.AdminEditScope
Tff7b72import T7ee787org.meshtastic.core.repository.RadioConfigRepository
Tff7b72import T7ee787org.meshtastic.core.repository.RadioController
Tff7b72import T7ee787org.meshtastic.proto.ChannelSet
Tff7b72import T7ee787org.meshtastic.proto.Config
Tff7b72import T7ee787org.meshtastic.proto.DeviceProfile
Tff7b72import T7ee787org.meshtastic.proto.LocalConfig
Tff7b72import T7ee787org.meshtastic.proto.LocalModuleConfig
Tff7b72import T7ee787org.meshtastic.proto.ModuleConfig
Tff7b72import T7ee787org.meshtastic.proto.User
T8b949e/** Use case for installing a device profile onto a radio. */
Tf0883e@Single
Tff7b72open Tff7b72class T56d364InstallProfileUseCase
Tff7b72constructorTb4b4b4(
Tff7b72private Tff7b72val Te6edf3radioControllerTb4b4b4: Te6edf3RadioControllerTb4b4b4,
Tff7b72private Tff7b72val Te6edf3radioConfigRepositoryTb4b4b4: Te6edf3RadioConfigRepositoryTb4b4b4,
Tb4b4b4) Tb4b4b4{
T8b949e/**
* Installs the provided [DeviceProfile] onto the radio at [destNum].
*
* @param destNum The destination node number.
* @param profile The device profile to install.
* @param currentUser The current user configuration of the destination node (to preserve names if not in profile).
* @throws org.meshtastic.core.repository.PacketQueueRejectedException when any profile write is refused locally.
* @throws org.meshtastic.core.repository.EditSettingsTransactionException when the begin or commit boundary is
* refused locally.
* @throws org.meshtastic.core.repository.LocalNodeUnavailableException when a fixed-position profile is installed
* before the local node identity is available.
* @throws MalformedMeshtasticUrlException when the profile channel URL or channel set is invalid. This is raised
* before the edit transaction opens, so no partial profile is applied.
*/
Tff7b72open Tff7b72suspend Tff7b72operator Tff7b72fun Td2a8ffinvokeTb4b4b4(
Te6edf3destNumTb4b4b4: Tffa657IntTb4b4b4,
Te6edf3profileTb4b4b4: Te6edf3DeviceProfileTb4b4b4,
Te6edf3currentUserTb4b4b4: Te6edf3User?Tb4b4b4,
Te6edf3currentLoraConfigTb4b4b4: Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTff7b72?Tb4b4b4,
Te6edf3isLocalTb4b4b4: Tffa657BooleanTb4b4b4,
Tb4b4b4) Tb4b4b4{
T8b949e// Decode and validate before opening the radio transaction. A malformed channel URL must not leave an edit
T8b949e// session open or allow the rest of the profile to be partially applied.
Tff7b72val Te6edf3channelSet Tff7b72= Te6edf3profileTb4b4b4.Te6edf3channel_urlTff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isNotBlankTb4b4b4(Tb4b4b4) Tb4b4b4}Tff7b72?.Te6edf3letTb4b4b4(Tff7b72::Te6edf3parseProfileChannelSetTb4b4b4)
Tff7b72val Te6edf3desiredLoraConfig Tff7b72= Te6edf3channelSetTff7b72?.Te6edf3lora_config Tff7b72?: Te6edf3profileTb4b4b4.Te6edf3configTff7b72?.Te6edf3lora
Tff7b72val Te6edf3replacementPlan Tff7b72=
Te6edf3channelSetTff7b72?.Te6edf3let Tb4b4b4{
Tff7b72try Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3toChannelReplacementPlanTb4b4b4(
Te6edf3currentSettings Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3fallbackLoraConfig Tff7b72= Te6edf3profileTb4b4b4.Te6edf3configTff7b72?.Te6edf3lora Tff7b72?: Te6edf3currentLoraConfigTb4b4b4,
Te6edf3requirePrimary Tff7b72= Tff7b72trueTb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalArgumentExceptionTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3MalformedMeshtasticUrlExceptionTb4b4b4(Ta5d6ff"Ta5d6ffInvalid channel set in device profileTa5d6ff"Tb4b4b4, Te6edf3eTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72val Te6edf3loraConfigToWrite Tff7b72= Te6edf3desiredLoraConfigTff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657it Tff7b72!Tff7b72= Te6edf3currentLoraConfig Tb4b4b4}
Te6edf3radioControllerTb4b4b4.Te6edf3editSettingsTb4b4b4(Te6edf3destNumTb4b4b4) Tb4b4b4{
Te6edf3installOwnerTb4b4b4(Te6edf3profileTb4b4b4, Te6edf3currentUserTb4b4b4)
Te6edf3installConfigTb4b4b4(Te6edf3profileTb4b4b4.Te6edf3configTb4b4b4)
Te6edf3installFixedPositionTb4b4b4(Te6edf3profileTb4b4b4.Te6edf3fixed_positionTb4b4b4)
Te6edf3installModuleConfigTb4b4b4(Te6edf3profileTb4b4b4.Te6edf3module_configTb4b4b4)
Te6edf3installChannelsAndLoraTb4b4b4(Te6edf3replacementPlanTb4b4b4, Te6edf3loraConfigToWriteTb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3isLocal Tff7b72&Tff7b72& Tb4b4b4(Te6edf3replacementPlan Tff7b72!Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3loraConfigToWrite Tff7b72!Tff7b72= Tff7b72nullTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3withContextTb4b4b4(Te6edf3NonCancellableTb4b4b4) Tb4b4b4{
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3updateChannelSetTb4b4b4(
Te6edf3settingsList Tff7b72= Te6edf3replacementPlanTff7b72?.Te6edf3normalizedSettingsTb4b4b4,
Te6edf3loraConfig Tff7b72= Te6edf3loraConfigToWriteTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffparseProfileChannelSetTb4b4b4(Te6edf3urlTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Te6edf3ChannelSet Tff7b72= Tff7b72try Tb4b4b4{
Te6edf3CommonUriTb4b4b4.Te6edf3parseTb4b4b4(Te6edf3urlTb4b4b4)Tb4b4b4.Te6edf3toChannelSetTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3IllegalArgumentExceptionTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3MalformedMeshtasticUrlExceptionTb4b4b4(Ta5d6ff"Ta5d6ffInvalid channel URL in device profileTa5d6ff"Tb4b4b4, Te6edf3eTb4b4b4)
Tb4b4b4}
T8b949e// is_licensed is deliberately not installed here: enabling ham mode is a dedicated onboarding flow
T8b949e// (set_ham_mode — rewrites the owner, disables encryption, applies tx power/frequency) that a plain
T8b949e// set_owner would bypass, leaving the radio flagged licensed without those required side effects.
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3AdminEditScopeTb4b4b4.Td2a8ffinstallOwnerTb4b4b4(Te6edf3profileTb4b4b4: Te6edf3DeviceProfileTb4b4b4, Te6edf3currentUserTb4b4b4: Te6edf3User?Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3profileTb4b4b4.Te6edf3long_name Tff7b72!Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3profileTb4b4b4.Te6edf3short_name Tff7b72!Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3profileTb4b4b4.Te6edf3is_unmessagable Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3currentUserTff7b72?.Te6edf3let Tb4b4b4{
Te6edf3setOwnerTb4b4b4(
Tffa657itTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3long_name Tff7b72= Te6edf3profileTb4b4b4.Te6edf3long_name Tff7b72?: Tffa657itTb4b4b4.Te6edf3long_nameTb4b4b4,
Te6edf3short_name Tff7b72= Te6edf3profileTb4b4b4.Te6edf3short_name Tff7b72?: Tffa657itTb4b4b4.Te6edf3short_nameTb4b4b4,
Te6edf3is_unmessagable Tff7b72= Te6edf3profileTb4b4b4.Te6edf3is_unmessagable Tff7b72?: Tffa657itTb4b4b4.Te6edf3is_unmessagableTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3AdminEditScopeTb4b4b4.Td2a8ffinstallConfigTb4b4b4(Te6edf3configTb4b4b4: Te6edf3LocalConfig?Tb4b4b4) Tb4b4b4{
Te6edf3configTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3lc Tff7b72-Tff7b72>
Te6edf3lcTb4b4b4.Te6edf3deviceTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3device Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lcTb4b4b4.Te6edf3positionTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3position Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lcTb4b4b4.Te6edf3powerTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3power Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lcTb4b4b4.Te6edf3networkTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3network Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lcTb4b4b4.Te6edf3displayTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3display Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lcTb4b4b4.Te6edf3bluetoothTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3bluetooth Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lcTb4b4b4.Te6edf3securityTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3security Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3AdminEditScopeTb4b4b4.Td2a8ffinstallFixedPositionTb4b4b4(Te6edf3fixedPositionTb4b4b4: Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3PositionTff7b72?Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3fixedPosition Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3setFixedPositionTb4b4b4(Te6edf3PositionTb4b4b4(Te6edf3fixedPositionTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3AdminEditScopeTb4b4b4.Td2a8ffinstallModuleConfigTb4b4b4(Te6edf3moduleConfigTb4b4b4: Te6edf3LocalModuleConfig?Tb4b4b4) Tb4b4b4{
Te6edf3moduleConfigTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3lmc Tff7b72-Tff7b72>
Te6edf3installModuleConfigPart1Tb4b4b4(Te6edf3lmcTb4b4b4)
Te6edf3installModuleConfigPart2Tb4b4b4(Te6edf3lmcTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3AdminEditScopeTb4b4b4.Td2a8ffinstallModuleConfigPart1Tb4b4b4(Te6edf3lmcTb4b4b4: Te6edf3LocalModuleConfigTb4b4b4) Tb4b4b4{
Te6edf3lmcTb4b4b4.Te6edf3mqttTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3mqtt Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3serialTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3serial Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3external_notificationTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3external_notification Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3store_forwardTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3store_forward Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3range_testTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3range_test Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3telemetryTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3telemetry Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3canned_messageTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3canned_message Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3audioTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3audio Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3AdminEditScopeTb4b4b4.Td2a8ffinstallModuleConfigPart2Tb4b4b4(Te6edf3lmcTb4b4b4: Te6edf3LocalModuleConfigTb4b4b4) Tb4b4b4{
Te6edf3lmcTb4b4b4.Te6edf3remote_hardwareTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3remote_hardware Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3neighbor_infoTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3neighbor_info Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3ambient_lightingTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3ambient_lighting Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3detection_sensorTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3detection_sensor Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3paxcounterTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3paxcounter Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3statusmessageTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3statusmessage Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3lmcTb4b4b4.Te6edf3takTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setModuleConfigTb4b4b4(Te6edf3ModuleConfigTb4b4b4(Te6edf3tak Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Te6edf3AdminEditScopeTb4b4b4.Td2a8ffinstallChannelsAndLoraTb4b4b4(
Te6edf3replacementPlanTb4b4b4: Te6edf3ChannelReplacementPlan?Tb4b4b4,
Te6edf3loraConfigTb4b4b4: Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTff7b72?Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3replacementPlanTff7b72?.Te6edf3channelWritesTff7b72?.Te6edf3forEach Tb4b4b4{ Te6edf3setChannelTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Te6edf3loraConfigTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3lora Tff7b72= Tffa657itTb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.08s